package com.hanwei.uap.acceptors.sstn.channel;

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.hanwei.uap.acceptors.api.channel.ChannelManager;
import com.hanwei.uap.acceptors.api.constants.ChannelKey;
import com.hanwei.uap.acceptors.api.constants.Server;
import com.hanwei.uap.acceptors.api.utils.ChannelUtils;
import com.hanwei.uap.common.constant.Common;
import com.hanwei.uap.common.data.check.CRC16;
import com.hanwei.uap.common.util.ByteUtil;
import com.hanwei.uap.common.util.bytes.SstnUtil;
import com.hanwei.uap.model.po.Command;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class NettyChannelManager implements ChannelManager {
    private Logger log = LoggerFactory.getLogger("command");
    private BiMap<String, Channel> deviceIdChannelMap = HashBiMap.create(new ConcurrentHashMap<String, Channel>());
    private String commandRspQname = Server.DEFAULT_Q_COMMAND_RSP;
    private String serverHost = Server.DEFAULT_BIND_HOST;
    private int serverPort = Server.DEFAULT_BIND_PORT;
    @Autowired
    private Environment env;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @PostConstruct
    private void init() {
        if (env.getProperty("uap.server.host") != null) {
            serverHost = env.getProperty("uap.server.host");
        }
        if (env.getProperty("uap.server.port") != null) {
            serverPort = env.getProperty("uap.server.port", Integer.class);
        }
        if (env.getProperty("uap.qname.commandrsp") != null) {
            commandRspQname = env.getProperty("uap.qname.commandrsp");
        }
        commandRspQname = commandRspQname + "_" + serverHost + "_" + serverPort;
    }
    @Override
    public void add(String deviceId, Channel channel) {
        deviceIdChannelMap.put(deviceId, channel);
    }

    @Override
    public Channel get(String deviceId) {
        return deviceIdChannelMap.get(deviceId);
    }

    @Override
    public Channel remove(String deviceId) {
        return deviceIdChannelMap.remove(deviceId);
    }

    @Override
    public String remove(Channel channel) {
       return deviceIdChannelMap.inverse().remove(channel);
    }

    @Override
    public Channel removeAndClose(String deviceId) {
        Channel channel = deviceIdChannelMap.remove(deviceId);
        if (null != channel)
            channel.close();
        return channel;
    }
    @Override
    public int size() {
        return deviceIdChannelMap.size();
    }

    @Override
    public boolean sendCommand(Command command) throws Exception{
        Channel channel = deviceIdChannelMap.get(command.getDeviceId());
        if(channel==null){
            if (log.isWarnEnabled()){
                log.warn("Send Fail.DeviceId:{} Is Offline.", command.getDeviceId());
            }
            return false;
        }

        if (!StringUtils.isEmpty(command.getCmd())) {
            byte[] v = ByteUtil.hex2byte(command.getCmd());
            // 除同步时间命令外已进行了CRC码的设置和字符转义
            if(Common.CMD_CODE_SYNTIME.equals(command.getCode())){
                v = ByteUtil.hex2byte(command.getCmd().replace("${curtime}", SstnUtil.getTimeHex()));
            }
            String deviceFullId = ChannelUtils.getDeviceFullId(channel, ChannelKey.DEVICEFULLID);
            //设置设备ID和类型
            byte[] d = ByteUtil.hex2byte(deviceFullId);
            v[1] = d[0];
            v[2] = d[1];
            v[3] = d[2];
            v[4] = d[3];
            v[5] = d[4];
            v[6] = d[5];
            v[7] = d[6];
            v[8] = d[7];
            v[9] = d[8];
            v[10] = d[9];
            CRC16.putCrc16(v);
            byte[] b = SstnUtil.transfer(v);
            ByteBuf cmdBuf = Unpooled.wrappedBuffer(b);
            Thread.sleep(2000);
            channel.writeAndFlush(cmdBuf);
            String cmdhex = ByteUtil.byte2hex(b);
            if (log.isInfoEnabled()){
                log.info("Send Command Success.ChannelId:{}, DeviceId:{}, Command:{}", channel.id().asShortText(), command.getDeviceId(), cmdhex);
            }
//            long cmdSn = command.getCmdSn();
//            BoundListOperations<String, String> list = stringRedisTemplate.boundListOps(commandRspQname);
//            list.leftPush(Long.toString(cmdSn) + "=" + cmdhex);
            return true;
        } else {
            if (log.isWarnEnabled()){
                log.warn("Send Fail.DeviceId:{}, Command Is Null.");
            }
        }
        return false;
    }
}

